package org.daochong.lang;

import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;

public class ThreadPool {
	
	private class PoolWorker extends Thread {
		private int taskId;

		private PoolWorker() {

		}

		public int getTaskId() {
			return taskId;
		}

		public void run() {

			while (flag) {
				Runnable r;
				synchronized (queue) {
					while (queue.isEmpty() && flag) {
						if (end)
							return;
						try {
							queue.wait();
						} catch (InterruptedException interruptedexception) {
						}
					}
					try {
						r = (Runnable) queue.firstElement();
						queue.removeElement(r);
					} catch (Exception e) {
						r = null;
					}
				}
				running.add(this);
				System.out.println((new StringBuffer("[\u4FE1\u606F]"))
						.append(getTaskId())
						.append("#\u4EFB\u52A1\u5DE5\u4F5C").toString());
				long last = System.currentTimeMillis();
				if (r != null) {
					try {
						r.run();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				running.remove(this);
				System.out.println((new StringBuffer("[\u4FE1\u606F]"))
						.append(getTaskId())
						.append("#\u4EFB\u52A1\u7ed3\u675f,\u6267\u884c")
						.append(System.currentTimeMillis() - last)
						.append("\u6BEB\u79D2]").toString());
			}
		}

		public void setTaskId(int taskId) {
			this.taskId = taskId;
		}

	}

	public static int DEFAULT_SIZE = 10;
	public static int DEFAULT_STEP = 5;
	public static int INITIAL_CAPACITY = 5;

	private int size = 10;
	private int step = 5;
	private int capacity = 5;

	private final Vector<PoolWorker> pools = new Vector<PoolWorker>();
	private final Vector<PoolWorker> running = new Vector<PoolWorker>();
	private final Vector<Runnable> queue = new Vector<Runnable>();

	private volatile boolean flag = true;
	private volatile boolean start = false;
	private volatile boolean end = false;

	public ThreadPool() {
		this.size = DEFAULT_SIZE;
		this.step = DEFAULT_STEP;
		this.capacity = INITIAL_CAPACITY;
	}

	public int getSize() {
		return size;
	}

	public void setSize(int size) {
		if (size > pools.size()) {
			this.size = size;
		}
	}

	public synchronized int getPoolSize() {
		return this.pools.size();
	}

	public int getCapacity() {
		return capacity;
	}

	public void setCapacity(int capacity) {
		if (!start && this.capacity > 0)
			this.capacity = capacity;
	}

	public int getStep() {
		return step;
	}

	public void setStep(int step) {
		if (step > 0)
			this.step = step;
	}

	public void start() {
		if(start){
			return;
		}
		ThreadClean clean = new ThreadClean();
		clean.pool= this;
		Runtime.getRuntime().addShutdownHook(clean);
		start = true;
		int s = Math.max(this.getCapacity(), queue.size());
		if (s > size)
			s = size;
		for (int i = 0; i < s; i++) {
			PoolWorker pw = new PoolWorker();
			pw.setTaskId((i + 1));
			pw.start();
			pools.add(pw);
		}
	}

	public synchronized int getRunningSize() {
		return this.running.size();
	}

	public synchronized int getFreeingSize() {
		return (this.pools.size() - this.running.size());
	}

	public boolean isStart() {
		return start;
	}

	public void execute(Runnable r) {
		if (end)
			return;
		synchronized (queue) {
			queue.addElement(r);
			if (!start)
				return;
			int psize = this.pools.size();
			if (psize < this.getSize() && this.getFreeingSize() == 0) {
				int c = this.getStep();
				if (psize + c > this.getSize()) {
					c = this.getSize() - psize;
				}
				for (int i = 0; i < c; i++) {
					PoolWorker pw = new PoolWorker();
					pw.setTaskId((i + 1 + psize));
					pw.start();
					pools.add(pw);
				}
			}
			queue.notify();
		}
	}

	public Vector<Runnable> shutDown() {
		System.out.println("close ThreadPool");
		end = true;
		synchronized (queue) {
			queue.notifyAll();
		}
		return queue;
	}

	public Vector<Runnable> shutDownImmediately() {
		System.out.println("close ThreadPool");
		end = true;
		flag = false;
		synchronized (queue) {
			queue.notifyAll();
		}
		for (PoolWorker worker : pools) {
			try {
				worker.interrupt();
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}
		return queue;
	}
	
	class ThreadClean extends Thread{
		private ThreadPool pool;		
		public void run(){
			if(this.pool!=null&&this.pool.isStart()){
				try{
					this.pool.shutDown();
					FileOutputStream fos = new FileOutputStream("D://temp/clean.txt");
					SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
					fos.write(("clean:"+sdf.format(new Date())).getBytes());
					fos.close();
				}catch(Throwable e){
					this.pool.shutDownImmediately();
				}
				
			}
		}
		
	}

}
